package main

import (
	"fmt"
)

func main() {
	//var 数组名称 [数组长度]数组类型
	var a [3]int //定义一个int类型的数组，长度为3
	var b [2]string
	b[0] = "tom"
	b[1] = "Bar"

	var c = [3]string{"tom", "jerry", "dog"} //初始化数组
	a1 := c[:]                               //左闭右开,取值
	d := [2]int{0, 1}

	var e = [...]string{"Hello", "World"} //省略数组长度
	fmt.Println(a, b, c, d, e, a1)

	//(1)遍历数组
	for i := 0; i < len(c); i++ {
		fmt.Println(c[i])
	}

	//(2)遍历数组,推荐使用这种
	for _, s := range c {
		fmt.Println(s)
	}

	//(3)切片,声明一个切片和声明一个数组一样，只要[]不填入数字就可以了
	var A []string
	fmt.Println(A)

	//(4)切片是引用类型，使用make函数声明初始化
	var B = make([]int, 2, 10) //开辟长度为10的空间，这个数组默认占2位长度
	C := make([]int, 2)        //后面为可变参数，可以省略
	fmt.Println(B, C)

	//(4.1)切片的赋值拷贝
	s12 := make([]int, 3) //[0 0 0]
	s22 := s12            //将s1直接赋值给s2，s1和s2共用一个底层数组
	s22[0] = 100
	fmt.Println(s12) //[100 0 0]
	fmt.Println(s22) //[100 0 0]

	//(5)切片的长度和容量
	//要检查切片是否为空，请始终使用len(s) == 0来判断，而不使用s == nil来判断
	fmt.Println(len(B), cap(B))

	//(6)初始化切片
	D := []int{1, 2, 3}
	E := [...]int{1, 2, 3, 4, 5, 6, 7}
	s1 := E[:] //左闭右开,取值
	fmt.Println(D, E, s1)

	//(7)添加元素
	F := []int{}
	F = append(F, 1)
	F = append(F, 2, 3, 4, 5, 6) //添加多个元素

	H := []int{1, 2}
	I := []int{3, 4, 5, 6}
	H = append(H, I...) //添加另一个切片
	fmt.Println(H)

	//(7.2)注意：通过var声明的零值切片可以在append()函数直接使用，无需初始化
	var s []int
	s = append(s, 1, 2, 3)

	//(8)删除 ,从切片中删除元素
	J := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	J = append(J[:2], J[3:]...)
	fmt.Println(J) //[30 31 33 34 35 36 37]

	//(9)copy()复制切片
	var K = []int{1, 2, 3, 4}
	var L = make([]int, len(K))
	copy(L, K) //使用copy()函数将切片k中的元素复制到切片l
	fmt.Println(L)

	s3 := []int{4, 5}
	s4 := []int{6, 7, 8, 9}
	copy(s4, s3)
	fmt.Println(s4) //[4 5 8 9]

	//(10)Go语言是支持多维数组的，我们这里以二维数组为例（数组中又嵌套数组）
	am := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	fmt.Println(am)       //[[北京 上海] [广州 深圳] [成都 重庆]]
	fmt.Println(am[2][1]) //支持索引取值:重庆
	//二维数组的遍历
	for _, v1 := range am {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}

	//(11)注意：多维数组只有第一层可以使用...来让编译器推导数组长度
	amn := [...][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	fmt.Println(amn)

	//(12)数组是值类型，赋值和传参会复制整个数组。因此改变副本的值，不会改变本身的值。
	abc := [3]int{10, 20, 30}
	modifyArray(abc) //在modify中修改的是a的副本x
	fmt.Println(a)   //[10 20 30]
	bac := [3][2]int{
		{1, 1},
		{1, 1},
		{1, 1},
	}
	modifyArray2(bac) //在modify中修改的是b的副本x
	fmt.Println(bac)  //[[1 1] [1 1] [1 1]]

	/*数组支持 “==“、”!=” 操作符，因为内存总是被初始化过的。
	[n]*T表示指针数组：“存放指针的数组”
	*[n]T表示数组指针：指向数组的指针
	*/
}
func modifyArray(x [3]int) {
	x[0] = 100
	fmt.Println("函数内部的：", x)
}

func modifyArray2(x [3][2]int) {
	x[2][0] = 100
	fmt.Println("函数内部的：", x)
}

func mon() {
	//切片是引用类型，所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化
	a := []int{1, 2, 3, 4, 5}
	b := a
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(b) //[1 2 3 4 5]
	b[0] = 1000
	fmt.Println(a) //[1000 2 3 4 5]
	fmt.Println(b) //[1000 2 3 4 5]

	// copy()复制切片
	aw := []int{1, 2, 3, 4, 5}
	cw := make([]int, 5, 5)
	copy(cw, aw)    //使用copy()函数将切片a中的元素复制到切片c
	fmt.Println(aw) //[1 2 3 4 5]
	fmt.Println(cw) //[1 2 3 4 5]
	cw[0] = 1000
	fmt.Println(aw) //[1 2 3 4 5]
	fmt.Println(cw) //[1000 2 3 4 5]

	// 从切片中删除元素,切片a中删除索引为index的元素，操作方法是a = append(a[:index], a[index+1:]...)
	aq := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	aq = append(aq[:2], aq[3:]...)
	fmt.Println(aq) //[30 31 33 34 35 36 37]

}
